package com.zkadmin.service.impl;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.mysema.query.types.Predicate;
import com.zkadmin.entity.SysMenu;
import com.zkadmin.entity.SysResource;
import com.zkadmin.entity.SysRole;
import com.zkadmin.entity.SysUser;
import com.zkadmin.helper.PasswordHelper;
import com.zkadmin.repository.SysRoleRepository;
import com.zkadmin.repository.SysUserRepository;
import com.zkadmin.service.SysUserService;
import com.zkadmin.util.AdminConstants;

@Service("sysUserService")
public class SysUserServiceImpl implements SysUserService {

	@Autowired
	private SysUserRepository repository;

	@Autowired
	private SysRoleRepository roleRepository;

	@Autowired
	private PasswordHelper passwordHelper;

	@Override
	public SysUser save(SysUser user) {
		return (user.getId() == null) ? createUser(user) : repository.save(user);
	}

	private SysUser createUser(SysUser user) {
		passwordHelper.encryptPassword(user);
		return repository.save(user);
	}

	@Override
	public SysUser changePassword(Long id, String newPassword) {
		SysUser user = repository.findOne(id);
		user.setPassword(newPassword);
		passwordHelper.encryptPassword(user);
		return repository.save(user);
	}

	@Override
	public Page<SysUser> paging(final Predicate predicate, Pageable pageable) {
		return repository.findAll(predicate, pageable);
	}

	@Override
	public SysUser findByUsername(String username) {
		return repository.findByUsername(username);
	}

	@Override
	public SysUser findByName(String name) {
		return repository.findByName(name);
	}

	@Override
	public SysUser findById(Long id) {
		return repository.findOne(id);
	}

	@Override
	public void correlationRoles(Long userId, Set<Long> removeRoleIds, Set<Long> roleIds) {
		SysUser user = findById(userId);
		if (user != null) {
			Set<SysRole> roles = user.getRoles();
			for (Iterator<SysRole> it = roles.iterator(); it.hasNext();) {
				if (removeRoleIds.contains(it.next().getId())) {
					it.remove();
				}
			}
			for (Long roleId : roleIds) {
				user.addRole(roleRepository.findOne(roleId));
			}
			repository.save(user);
		}
	}

	@Override
	public Set<String> findRoles(String username) {
		Set<String> userRoles = new HashSet<String>();
		SysUser user = findByUsername(username);
		if (user != null) {
			Set<SysRole> sysRoles = user.getRoles();
			for (SysRole sysRole : sysRoles) {
				userRoles.add(sysRole.getRole());
			}
		}
		return userRoles;
	}

	@Override
	public Set<String> findUserRoleResources(String username) {
		Set<String> userRoleResources = new HashSet<String>();
		SysUser user = findByUsername(username);
		if (user != null) {
			Set<SysRole> roles = user.getRoles();
			for (SysRole role : roles) {
				userRoleResources.addAll(getRoleResources(role));
			}
		}
		return userRoleResources;
	}

	@Override
	public void delete(Long id) {
		SysUser user = findById(id);
		if (user != null) {
			repository.delete(user);
		}
	}

	private Set<String> getRoleResources(SysRole role) {
		Set<String> roleResources = new HashSet<String>();
		Set<SysMenu> menus = role.getMenus();
		for (SysMenu menu : menus) {
			roleResources.add(AdminConstants.MENU_RESOURCE + menu.getCode());
		}

		Set<SysResource> resources = role.getResources();
		for (SysResource resource : resources) {
			roleResources.add(resource.getPermission());
		}
		return roleResources;
	}

	@Override
	public SysUser getCurrentSysUser() {
		String principal = (String) SecurityUtils.getSubject().getPrincipal();
		return (principal != null) ? findByUsername(principal) : null;
	}

}
